package com.hivekion.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hivekion.common.core.SystemConstant;
import com.hivekion.common.entity.PagedResultVo;
import com.hivekion.common.entity.TreeNode;
import com.hivekion.common.entity.vo.LoginUser;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.redis.RedisUtil;
import com.hivekion.common.security.SecurityUtils;
import com.hivekion.system.domain.*;
import com.hivekion.system.domain.vo.*;
import com.hivekion.system.mapper.SysUserAreasMapper;
import com.hivekion.system.mapper.SysUserMapper;
import com.hivekion.system.mapper.SysUserRolesMapper;
import com.hivekion.system.service.ISysAreaService;
import com.hivekion.system.service.ISysDeptService;
import com.hivekion.system.service.ISysUserAreasService;
import com.hivekion.system.service.ISysUserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户 业务层处理
 *
 * @author sutao
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    @Autowired
    SysUserMapper userMapper;
    @Autowired
    RedisUtil redisUtil;
    @Autowired
    ISysDeptService deptService;
    @Autowired
    private SysUserRolesMapper userRolesMapper;
    @Autowired
    private SysUserAreasMapper userAreasMapper;

    @Autowired
    private ISysUserAreasService sysUserAreasService;
    @Autowired
    private ISysAreaService areaService;

    @Value("${user.default.password}")
    private String default_password;

    @Override
    public PagedResultVo<SysUserViewVo> selectUserList(SysUserSearchPageInputVo inputVo) {
        QueryWrapper<SysUserViewVo> userLambdaQueryWrapper = Wrappers.query();
        QueryWrapper<SysUserAreas> userAreaLambdaQueryWrapper = Wrappers.query();
        List<String> userIds = new ArrayList<>();
        if (inputVo.getAreaId() != null) {
            userAreaLambdaQueryWrapper.eq("area_id", inputVo.getAreaId());
            userAreasMapper.selectList(userAreaLambdaQueryWrapper).stream().forEach(userArea -> userIds.add(userArea.getUserId()));

            if (userIds != null && userIds.size() > 0) {
                userLambdaQueryWrapper.in("u.id", userIds);
            } else {
                PagedResultVo<SysUserViewVo> resultVo =
                        new PagedResultVo<SysUserViewVo>(inputVo, 0, null);
                return resultVo;
            }
        }
        if (StringUtils.isNotEmpty(inputVo.getFilter())) {
            userLambdaQueryWrapper
                    .like("u.user_name", inputVo.getFilter())
                    .or()
                    .like("u.phone_number", inputVo.getFilter())
                    .or()
                    .like("u.nick_name", inputVo.getFilter())
            .or()
            .like("u.last_update",inputVo.getFilter());
        }
        if (inputVo.getStatus() != null && inputVo.getStatus() != -1) {
            userLambdaQueryWrapper.eq("u.status", inputVo.getStatus());
        }
        Page<SysUserViewVo> userPage = new Page<>(inputVo.getPageNum(), inputVo.getPageSize());
        userPage.addOrder(new OrderItem("u.create_time", false));
        IPage<SysUserViewVo> users = userMapper.selectUserList(userPage, userLambdaQueryWrapper);
        Integer total = (int) users.getTotal();
        PagedResultVo<SysUserViewVo> resultVo =
                new PagedResultVo<SysUserViewVo>(inputVo, total, users.getRecords());
        return resultVo;
    }

    public boolean create(SysUserCreateInputVo inputDto) {
        SysUser user = new SysUser();
        BeanUtils.copyProperties(inputDto, user);
        String password = DigestUtils.md5DigestAsHex(default_password.getBytes());
        user.setPassword(password);
        boolean bl = userMapper.insert(user) > 0; // 设置初始密码
        if (bl) {
            this.addUserRoles(user, inputDto.getRoles());
        }
        if (bl) {
            this.addUserAreas(user, inputDto.getAreaIds());
        }
        this.updateRedis();
        return true;
    }

    @Override
    public boolean update(SysUserUpdateInputVo inputVo) {
        SysUser user = getUser(inputVo.getId());
        BeanUtils.copyProperties(inputVo, user);
        if (userMapper.updateById(user) > 0) {
            this.updateUserRoles(user, inputVo.getRoles());
            this.updateUserAreas(user, inputVo.getAreaIds());
        }

        this.updateRedis();
        return true;
    }

    @Override
    public Boolean checkUserNameUnique(String userName, String userId) {
        SysUser info = userMapper.checkUserNameUnique(userName);
        if (info != null && !info.getId().equals(userId)) {
            return false;
        }
        return true;
    }

    /**
     * 判断邮箱地址是否唯一
     *
     * @param email
     * @return ture 已存在，false 不存在
     */
    @Override
    public Boolean checkEmailUnique(String email, String userId) {
        SysUser info = userMapper.checkEmailUnique(email);
        if (info != null && !info.getId().equals(userId)) {
            return false;
        }
        return true;
    }

    @Override
    public Boolean checkPhoneUnique(String phone, String userId) {
        SysUser info = userMapper.checkPhoneUnique(phone);
        if (info != null && !info.getId().equals(userId)) {
            return false;
        }
        return true;
    }

    @Override
    public boolean delete(String userId) {
        int c = userMapper.deleteById(userId);
        this.updateRedis();
        return c > 0;
    }

    @Override
    public boolean resetPwd(SysUserResetPwdVo pwdVo) {
        boolean bo = (checkPassword(pwdVo.getPassword())>2);
        if (!bo) {
            throw new BusinessException(500, "密码强度不符合要求！");
        }
        SysUser user = getUser(pwdVo.getId());
        String password = DigestUtils.md5DigestAsHex(pwdVo.getPassword().getBytes());
        user.setPassword(password);
        user.setLastUpdate(new Date(System.currentTimeMillis()));
        return userMapper.updateById(user) > 0;
    }

    @Override
    public boolean changeStatus(String userId, Integer status) {
        SysUser user = getUser(userId);
        if (user.getUserName().equals("admin")) {
            throw new BusinessException(500, "管理员账户不允许禁用。");
        }
        user.setStatus(status);
        int c = userMapper.updateById(user);
        this.updateRedis();
        return c > 0;
    }

    @Override
    public SysUserModelVo getInfo(String userId) {
        SysUser user = getUser(userId);
        SysUserModelVo vo = new SysUserModelVo();
        BeanUtils.copyProperties(user, vo);
        System.out.println(user.getLastUpdate());
        if (user.getLastUpdate() == null) {
            user.setLastUpdate(new Date(System.currentTimeMillis()));
            userMapper.updateById(user);
        } else {
            long l = user.getLastUpdate().getTime() + 7 * 24 * 60 * 60*1000;
            if (l < System.currentTimeMillis()) {
                vo.setPasswordStatus(true);
            }
        }
        // 获取用户角色
        QueryWrapper<SysUserRoles> rolesQueryWrapper = Wrappers.query();
        rolesQueryWrapper.eq("user_id", user.getId());
        List<String> roles =
                userRolesMapper.selectList(rolesQueryWrapper).stream()
                        .map(
                                item -> {
                                    return item.getRoleId();
                                })
                        .collect(Collectors.toList());
        vo.setRoles(roles);

        // 获取用户地区
        QueryWrapper<SysUserAreas> areasQueryWrapper = Wrappers.query();
        areasQueryWrapper.eq("user_id", user.getId());
        List<String> areas =
                userAreasMapper.selectList(areasQueryWrapper).stream()
                        .map(
                                item -> {
                                    return item.getAreaId();
                                })
                        .collect(Collectors.toList());
        vo.setAreaIds(areas);
        return vo;
    }

    private SysUser getUser(String userId) {
        SysUser user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException(500, "未找到用户信息！");
        }
        return user;
    }

    @Override
    public SysUser getUserByUserName(String userName) {
        QueryWrapper<SysUser> wrapper = Wrappers.query();
        wrapper.eq("user_name", userName);
        SysUser user = userMapper.selectOne(wrapper);
        if (user == null) {
            throw new BusinessException(500, "未找到用户信息！");
        }
        return user;
    }

    @Override
    public String getUserName(String userIds) {
        List<String> userId = Arrays.asList(userIds.split(",").clone());
        List<SysUser> users = userMapper.selectBatchIds(userId);
        List<String> userNames =
                users.stream().map(SysUser::getNickName).collect(Collectors.toList());
        return StringUtils.join(userNames, ",");
    }

    /*
     * 获取用户的所有权限码
     * */
    @Override
    public List<String> getPermissions(String userId) {
        List<String> data = userMapper.selectUserPermission(userId);
        return data.stream().distinct().collect(Collectors.toList());
    }

    private void updateUserRoles(SysUser user, List<String> roles) {
        // 获取已经存在的 角色
        // 将用户原有的角色全部删除
        QueryWrapper<SysUserRoles> rolesQueryWrapper = Wrappers.query();
        rolesQueryWrapper.eq("user_id", user.getId());
        List<String> oldRoles =
                userRolesMapper.selectList(rolesQueryWrapper).stream()
                        .map(
                                item -> {
                                    return item.getRoleId();
                                })
                        .collect(Collectors.toList());
        // 如果用户之前没有角色信息则不需要进行删除
        if (oldRoles != null && oldRoles.size() > 0) {
            LambdaQueryWrapper<SysUserRoles> deleteWrapper = Wrappers.lambdaQuery();
            deleteWrapper.eq(SysUserRoles::getUserId, user.getId());
            userRolesMapper.delete(deleteWrapper);
        }
        // 新增用户角色
        if (roles != null && roles.size() > 0) {
            this.addUserRoles(user, roles);
        }
    }

    private void updateUserAreas(SysUser user, List<String> areas) {
        // 获取已经存在的 角色
        // 将用户原有的角色全部删除
        QueryWrapper<SysUserAreas> areasQueryWrapper = Wrappers.query();
        areasQueryWrapper.eq("user_id", user.getId());
        List<String> oldAreas =
                userAreasMapper.selectList(areasQueryWrapper).stream()
                        .map(
                                item -> {
                                    return item.getAreaId();
                                })
                        .collect(Collectors.toList());
        // 如果用户之前没有角色信息则不需要进行删除
        if (oldAreas != null && oldAreas.size() > 0) {
            LambdaQueryWrapper<SysUserAreas> deleteWrapper = Wrappers.lambdaQuery();
            deleteWrapper.eq(SysUserAreas::getUserId, user.getId());
            userAreasMapper.delete(deleteWrapper);
        }
        // 新增用户角色
        if (areas != null && areas.size() > 0) {
            this.addUserAreas(user, areas);
        }
    }

    private void addUserRoles(SysUser user, List<String> roles) {
        if (roles != null && roles.size() > 0) {
            roles.stream()
                    .forEach(
                            item -> {
                                SysUserRoles role = new SysUserRoles();
                                role.setUserId(user.getId());
                                role.setRoleId(item.trim());
                                userRolesMapper.insert(role);
                            });
        }
    }

    private void addUserAreas(SysUser user, List<String> areas) {
        if (areas != null && areas.size() > 0) {
            areas.stream()
                    .forEach(
                            item -> {
                                SysUserAreas role = new SysUserAreas();
                                role.setUserId(user.getId());
                                role.setAreaId(item.trim());
                                userAreasMapper.insert(role);
                            });
        }
    }

    public List<SysUser> getAllUser() {
        if (redisUtil.hasKey(SystemConstant.redis_user_data)) {
            List<SysUser> list =
                    JSON.parseArray(
                            redisUtil.get(SystemConstant.redis_user_data).toString(),
                            SysUser.class);
            return list;
        } else {
            List<SysUser> users = userMapper.selectList(null);
            redisUtil.set(SystemConstant.redis_user_data, JSON.toJSONString(users));
            return users;
        }
    }

    @Override
    public List<TreeNode> getUserTree() {

        List<SysDept> parentDepts =
                deptService.getAllList().stream()
                        .filter(x -> StringUtils.isEmpty(x.getParentId()))
                        .collect(Collectors.toList());
        return this.getTreeNode(parentDepts);
    }

    @Override
    public List<TreeNode> getStatisticianByArea(String areaCode) {
        return userMapper.getStatisticianByArea(areaCode);
    }

    @Override
    public List<TreeNode> getUserArea() {
        LoginUser user = SecurityUtils.getCurrentLoginUser();
        String treeDataKey = String.format("%s:%s", SystemConstant.redis_area_tree_data, user.getUserId());
        if (redisUtil.hasKey(treeDataKey)) {
            return JSON.parseArray(redisUtil.get(treeDataKey).toString(), TreeNode.class);
        }
        // 获取用户地区
        QueryWrapper<SysUserAreas> areasQueryWrapper = Wrappers.query();
        areasQueryWrapper.eq("user_id", user.getUserId());
        List<String> areas =
                userAreasMapper.selectList(areasQueryWrapper).stream()
                        .map(
                                item -> item.getAreaId())
                        .collect(Collectors.toList());
        List<TreeNode> treeNodes = new ArrayList<>();
        List<SysArea> allArea = areaService.getAllList();

        if (areas != null && areas.size() > 0) {
            areas.forEach(item -> {
                Optional<SysArea> first = allArea.stream().filter(x -> item.equals(x.getId())).findFirst();
                if (first.isPresent()) {
                    SysArea area = first.get();
                    TreeNode node = new TreeNode();
                    node.setKey(area.getId());
                    node.setValue(area.getId());
                    node.setTitle(area.getName());
                    node.setChildren(areaService.getChildrenNodeList(area.getId()));
                    treeNodes.add(node);
                }
            });
        }
        redisUtil.set(treeDataKey, JSON.toJSONString(treeNodes));
        return treeNodes;
    }

    @Override
    public boolean clearUserTreeData() {
        LoginUser user = SecurityUtils.getCurrentLoginUser();
        String treeDataKey = String.format("%s:%s", SystemConstant.redis_area_tree_data, user.getUserId());
        redisUtil.deleteKey(treeDataKey);
        return !redisUtil.hasKey(treeDataKey);
    }

    @Override
    public void delDuplicateUser() {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("user_name");
        List<SysUser> allUsers = userMapper.selectList(queryWrapper);
        Map<String, List<String>> map = new HashMap<>();
        for (SysUser user : allUsers) {
            String userName = user.getUserName();
            if (!map.containsKey(userName)) {
                map.put(userName, new ArrayList<>());
            }
            map.get(userName).add(user.getId());
        }

        for (String phone : map.keySet()) {
            List<String> userIdList = map.get(phone);
            QueryWrapper<SysUserAreas> query = new QueryWrapper<>();
            query.in("user_id", userIdList);
            List<SysUserAreas> userAreasList = sysUserAreasService.list(query);

            if (userIdList.size() > 1) {
                String userId = userIdList.get(0);
                for (SysUserAreas sysUserAreas : userAreasList) {
                    sysUserAreas.setUserId(userId);
                }
                sysUserAreasService.saveOrUpdateBatch(userAreasList);


                userIdList.remove(0);
                removeByIds(userIdList);
            }
        }
    }

    @Override
    public Set<String> importExcel(MultipartFile file) {
        Workbook wb = readExcel(file); //文件
        Sheet sheet = wb.getSheetAt(0); //sheet

        Map<String, Set<String>> map = new HashMap<>();

        Set<String> addressList = new HashSet<>();
        DecimalFormat df = new DecimalFormat("#####");
        for (int i = 1; true; i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                break;
            }
            Cell phoneCell = row.getCell(0);
            CellType cellTypeEnum = phoneCell.getCellTypeEnum();
            String phoneNum = "";
            if (cellTypeEnum == CellType.NUMERIC) {
                phoneNum = df.format(phoneCell.getNumericCellValue());
            } else {
                phoneNum = phoneCell.getStringCellValue();
            }

            Cell addressCell = row.getCell(4);
            String address = addressCell.getStringCellValue();

            if (!map.containsKey(phoneNum)) {
                map.put(phoneNum, new HashSet<>());
            }
            map.get(phoneNum).add(address.trim());
        }

        for (String phone : map.keySet()) {
            QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_name", phone);
            List<SysUser> sysUsers = userMapper.selectList(queryWrapper);
            if (sysUsers != null && sysUsers.size() > 0) {
                SysUser user = sysUsers.get(0);

                QueryWrapper<SysUserAreas> query = new QueryWrapper<>();
                query.eq("user_id", user.getId());
                sysUserAreasService.remove(query);

                Set<String> address = map.get(phone);

                List<SysUserAreas> list = new ArrayList<>();
                for (String addr : address) {
                    QueryWrapper<SysArea> areaQueryWrapper = new QueryWrapper<>();
                    areaQueryWrapper.eq("full_name", addr);
                    SysArea area = areaService.getOne(areaQueryWrapper);

                    if (area != null) {
                        SysUserAreas sysUserAreas = new SysUserAreas();
                        sysUserAreas.setUserId(user.getId());
                        sysUserAreas.setAreaId(area.getId());
                        list.add(sysUserAreas);
                    } else {
                        addressList.add(addr);
                    }
                }
                sysUserAreasService.saveOrUpdateBatch(list);
            }
        }

        return addressList;
    }

    //读取excel
    private Workbook readExcel(MultipartFile multipartFile) {
        Workbook wb = null;
        if (multipartFile == null) {
            return null;
        }
        String filename = multipartFile.getOriginalFilename();
        String extString = filename.substring(filename.lastIndexOf("."));
        InputStream is = null;
        try {
            is = multipartFile.getInputStream();
            if (".xls".equals(extString)) {
                return wb = new HSSFWorkbook(is);
            } else if (".xlsx".equals(extString)) {
                return wb = new XSSFWorkbook(is);
            } else {
                return wb = null;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return wb;
    }

    private List<TreeNode> getTreeNode(List<SysDept> depts) {
        List<TreeNode> list = new ArrayList<>();
        if (depts != null && depts.size() > 0) {
            depts.forEach(
                    item -> {
                        TreeNode node = new TreeNode();
                        node.setTitle(item.getDeptName());
                        node.setKey(item.getId());
                        node.setValue(item.getId());
                        node.setData(0);
                        List<TreeNode> children = new ArrayList<>();
                        // 查询下级部门
                        List<SysDept> childrenDept =
                                deptService.getAllList().stream()
                                        .filter(x -> item.getId().equals(x.getParentId()))
                                        .collect(Collectors.toList());
                        children.addAll(this.getTreeNode(childrenDept));
                        // 查询部门下人员
                        List<SysUser> users =
                                this.getAllUser().stream()
                                        .filter(x -> item.getId().equals(x.getDeptId()))
                                        .collect(Collectors.toList());
                        for (SysUser user : users) {
                            TreeNode cnode = new TreeNode();
                            cnode.setData(1);
                            cnode.setValue(user.getId());
                            cnode.setKey(user.getId());
                            cnode.setTitle(user.getNickName());
                            children.add(cnode);
                        }
                        if (children.size() > 0) {
                            node.setChildren(children);
                            node.setLeaf(false);
                        } else {
                            node.setLeaf(true);
                        }
                        list.add(node);
                    });
        }
        return list;
    }

    private void updateRedis() {
        List<SysUser> users = userMapper.selectList(null);
        redisUtil.set(SystemConstant.redis_user_data, JSON.toJSONString(users));
    }

    private int checkPassword(String password) {
        int level = 0;
        //数字ASCII 48-57  大写65-90  小写97-122
        if (password.isEmpty()) {
            throw new BusinessException(500, "密码不能为空");
        }
        char arr[] = password.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] >= 48 && arr[i] <= 57) {
                level = level + 1;
                break;
            }
        }
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] >= 65 && arr[i] <= 90) {
                level = level + 1;
                break;
            }
        }
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] >= 97 && arr[i] <= 122) {
                level = level + 1;
                break;
            }
        }
        for (int i = 0; i < arr.length; i++) {
            if ((arr[i] > 20 && arr[i] < 48) || (arr[i] > 57 && arr[i] < 65) || (arr[i] > 90 && arr[i] < 97) || arr[i] > 122 && arr[i] <= 126) {
                level = level + 1;
                break;
            }
        }
        return level;
    }

}
